#pragma once

#include <string>

#include "leveldb/status.h"
#include "leveldb/slice.h"


namespace leveldb {
    class Env;

    class WritableFile;
    class SequentialFile;

    namespace log {
        class Reader;
        class NewWriter;
    }
}
class Size;

class Stream  {
public:
    class InternalAppender {
    public:
        InternalAppender(leveldb::Env * env, const std::string & name, uint64_t startPosition);
        ~InternalAppender();

        leveldb::Status append(const std::string & bytes);

    private:
        leveldb::Status open() ;
        void close();

    private: 
        leveldb::Env * env_;
        const std::string & name_;
        leveldb::WritableFile * writableFile_;
        leveldb::log::NewWriter * writer_;

        uint64_t startPosition_ = 0;
    };
    class InternalReader {
    public:
        InternalReader(leveldb::Env * env, const std::string & name);
        ~InternalReader();

        bool hasNext() const ;
        void next() ;
        
        const leveldb::Slice &  current() ;

    private:
        leveldb::Status open();
        void close();

    private:
        bool checkFileLength();

    private:
        leveldb::Env * env_;
        const std::string & name_;

        leveldb::SequentialFile * readableFile_;
        leveldb::log::Reader * reader_;

        bool isEof_;
        leveldb::Slice * record_;
        std::string scratch_;
    };


    Stream(const std::string & name);

    ~Stream() ;

    leveldb::Env * env();

    Size & size();
    const Size & size() const;


	const std::string name() const  ;


    Stream::InternalAppender * createAppender(uint64_t startPosition = 0);
    Stream::InternalReader * createReader();

    bool exists() const;
    leveldb::Status length(uint64_t & len);
    leveldb::Status touch();
    leveldb::Status destroy();

private:
    leveldb::Env * env_ = nullptr;
    Size * size_ = nullptr;
    std::string name_;
};
